package com.example.im.endpoint;

import com.example.im.app.service.WebSocketMessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.util.ArrayList;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author PC
 */
@Component
@ServerEndpoint("/ws")
public class WebSocketEndpoint {

    private final static Logger logger = LoggerFactory.getLogger(WebSocketEndpoint.class);

    public static final ConcurrentHashMap<Integer, WebSocketEndpoint> WEB_SOCKET_ENDPOINT_MAP = new ConcurrentHashMap<>();

    /**
     * redis中用户SessionMap
     */
    public static final String ONLINE_USER = "cus:ws:online-user";

    private Session session;
    private static WebSocketMessageService webSocketMessageService;

    private static RedisTemplate<String, String> redisTemplate;

    @Autowired
    public void setWebSocketMessageService(WebSocketMessageService webSocketMessageService) {
        WebSocketEndpoint.webSocketMessageService = webSocketMessageService;
    }

    @Autowired
    public void setRedisTemplate(RedisTemplate<String, String> redisTemplate) {
        WebSocketEndpoint.redisTemplate = redisTemplate;
    }

    /**
     * 打开ws连接
     *
     * @param session 会话
     */
    @OnOpen
    public void onOpen(Session session) {
        //连接成功
        String userName = getUserName(session);
        logger.info("The connection is successful:" + getUserName(session));
        this.session = session;
        //是有hash冲突的可能性的，不过触发概率很低，可以忽略
        int hashCode = userName.hashCode();
        redisTemplate.opsForValue().setBit(ONLINE_USER, hashCode, true);
        WEB_SOCKET_ENDPOINT_MAP.put(hashCode, this);
    }

    /**
     * 断开ws连接
     *
     * @param session 会话
     */
    @OnClose
    public void onClose(Session session) {
        String userName = getUserName(session);
        int hashCode = userName.hashCode();
        redisTemplate.opsForValue().setBit(ONLINE_USER, hashCode, false);
        WEB_SOCKET_ENDPOINT_MAP.remove(hashCode);
        //断开连接
        logger.info("Disconnect:" + userName);
    }

    /**
     * 接收到的消息
     *
     * @param message 消息内容
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        //接收消息
        String sendUserName = getUserName(session);
        webSocketMessageService.sendMessage(sendUserName, message);
    }

    private String getUserName(Session session) {
        return Optional.ofNullable(session.getRequestParameterMap().get("userName")).orElse(new ArrayList<>())
                .stream().findFirst().orElse("anonymous_users");
    }

    public Session getSession() {
        return session;
    }

    public void setSession(Session session) {
        this.session = session;
    }
}
